#include <linux/init.h>
#include <linux/module.h>
#include<linux/spi/spi.h>
#include "pro.h"

const char shutdown = 0;

struct cdev* cdev;
dev_t devno;
#if 0
unsigned int major = 0;
#else 
unsigned int major = 499;   //指定主设备号，三个驱动的主设备号不可以相同
#endif
unsigned int minor = 0;     //指定次设备号
struct class* cls;
struct device* dev;

struct spi_device* spii;

int T_H[4]={};

int m74hc595_open(struct inode* inode,struct file* file)
{
    return 0;
}

int m74hc595_close(struct inode* inode,struct file* file)
{
    return 0;
}

/* 接收 应用层程序解析好的 位码 与 断码
 * 点亮数码管，显示 二位数湿度 与 二位数温度 */
long m74hc595_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
    //通过SPI_L接收到cmd指令，通过whitch获得指定的 断码 或者 位码
    char whitch, ret;
    switch (cmd)
    {
    case SPI_L:
        ret = copy_from_user(&whitch, (void *)arg, sizeof(char));
        if (ret)
        {
            printk("copy_from_user failed\n");
            return -EIO;
        }
        spi_write(spii, &whitch, sizeof(char));
        break;
    }
    return 0;
}

//指定操作方法
struct file_operations fops={
    .open=m74hc595_open,
    .unlocked_ioctl=m74hc595_ioctl,
    .release=m74hc595_close,
};

//platform连接函数
int m74hc595_probe(struct spi_device *spi)
{
    int ret;
    spii=spi;
    // 1.分配对象
    cdev = cdev_alloc();
    if (NULL == cdev)
    {
        printk("分配对象空间失败\n");
        ret = -ENOMEM;
        goto ERR1;
    }
    // printk("分配对象空间成功\n");
    // 2.初始化驱动对象
    cdev_init(cdev, &fops);
    if (0 == major)
    {
        ret = alloc_chrdev_region(&devno, minor, 3, "m74hc595");
        if (ret)
        {
            printk("动态申请设备号失败\n");
            goto ERR2;
        }
        major = MAJOR(devno);
        minor = MINOR(devno);
    }
    else if (major > 0)
    {
        ret = register_chrdev_region(MKDEV(major, minor), 3, "m74hc595");
        if (ret)
        {
            printk("静态申请设备号失败\n");
            goto ERR2;
        }
    }
    // 3.注册对象
    ret = cdev_add(cdev, MKDEV(major, minor), 3);
    if (ret)
    {
        printk("驱动对象注册进内核失败\n");
        goto ERR3;
    }
    // printk("驱动对象注册进内核成功\n");
    cls = class_create(THIS_MODULE, "m74hc595");
    if (IS_ERR(cls))
    {
        printk("向上提交目录失败\n");
        goto ERR4;
    }
    // printk("向上提交目录成功\n");

    dev = device_create(cls, NULL, MKDEV(major, 0), NULL, "m74hc595");
    if (IS_ERR(dev))
    {
        printk("向上提交结点信息失败\n");
        goto ERR5;
    }
    return 0;
ERR5:
    device_destroy(cls, MKDEV(major, 0));
    class_destroy(cls);
ERR4:
    cdev_del(cdev);
ERR3:
    unregister_chrdev_region(MKDEV(major, minor), 3);
ERR2:
    kfree(cdev);
ERR1:
    return ret;
    return 0;

}

//卸载函数 释放申请的资源
int m74hc595_remove(struct spi_device *spi)
{
    int i;
    for(i=1;i<=10;i++)
    {
        spi_write(spi, &shutdown,sizeof(char));
    }
    device_destroy(cls, MKDEV(major, 0));
    class_destroy(cls);
    cdev_del(cdev);
    unregister_chrdev_region(MKDEV(major, minor), 3);
    kfree(cdev);
    return 0;
}

//设备树匹配表
struct of_device_id of_table[]={
    {.compatible="hqyj,m74hc595"},
    {},
};

//定义SPI对象并且初始化
struct spi_driver m74hc595 ={ 
    .probe=m74hc595_probe,
    .remove=m74hc595_remove,
    .driver={
        .name="m74hc595",
        .of_match_table=of_table,
    },
};
 
module_spi_driver(m74hc595); 
MODULE_LICENSE("GPL");